<template>
  <div class="machine-detail-wrapper">
    <!-- 卡片信息显示区域 -->
    <div v-if="cardInfo" class="card-info-bar">
      <div class="info-item">
        <img :src="tipsIcon" alt="提示" class="tips-icon" />
        <span class="info-text">计划编号：{{ cardInfo.title }}</span>
      </div>
      <div class="info-item">
        <img :src="tipsIcon" alt="提示" class="tips-icon" />
        <span class="info-text">计划名称：{{ cardInfo.planName }}</span>
      </div>
      <div class="info-item">
        <img :src="tipsIcon" alt="提示" class="tips-icon" />
        <span class="info-text">发布时间：{{ cardInfo.publishTime }}</span>
      </div>
      <div class="info-item">
        <img :src="tipsIcon" alt="提示" class="tips-icon" />
        <span class="info-text">有效期限：{{ cardInfo.validPeriod }}</span>
      </div>
      <div class="info-item">
        <img :src="tipsIcon" alt="提示" class="tips-icon" />
        <span class="info-text">创建时间：{{ cardInfo.createTime }}</span>
      </div>
    </div>

    <!-- 综述结论长条 -->
    <div class="summary-bar">
      <img :src="textIcon" alt="文本图标" class="summary-icon" />
      <span class="summary-text">综述结论</span>
    </div>

    <!-- 空数据状态 -->
    <div v-if="agentList.length === 0" class="empty-state">
      <div class="empty-icon">
        <img :src="nullImage" alt="暂无数据" />
      </div>
    </div>

    <div v-else class="three-column-layout">
      <!-- 左侧�? -->
      <div class="left-column">
        <div class="column-content">
          <div v-for="(agent, index) in agentList" :key="`${index}-${agentImages[index]}`" class="node-item" :class="{
            'selected': index === selectedAgentIndex,
            'no-data': !agent.hasData
          }" @click="selectAgent(index)">
            <img :src="agentImages[index]" :alt="agent.name" class="node-bg" />
            <span class="node-text">{{ agent.name }}</span>
            <img v-if="index === selectedAgentIndex" :src="jiantouImage" alt="箭头" class="node-arrow" />
          </div>
        </div>
      </div>

      <!-- 中间�?- 根据当前智能体类型决定是否显�?-->
      <div v-if="shouldShowMiddleColumn" class="middle-column">
        <div class="column-content">
          <div class="middle-title">节点</div>
          <div v-for="(node, index) in currentAgentNodes" :key="node.nodeId" class="middle-item"
            :class="{ 'selected': index === selectedNodeIndex }" @click="selectNode(index)">
            <span class="middle-item-text">{{ node.nodeId }}</span>
            <img :src="node.completed ? checkImage : notCheckImage" alt="check" class="middle-item-icon" />
            <div v-if="index === selectedNodeIndex && !node.completed" class="node-progress-bar"
              :style="{ width: currentNodeProgress + '%' }"></div>
            <div v-if="index === selectedNodeIndex && node.completed" class="node-progress-bar fade-out"
              :style="{ width: '100%' }"></div>
          </div>
        </div>
      </div>

      <!-- 右侧�? -->
      <div class="right-column" :class="{ 'full-width': !shouldShowMiddleColumn }" ref="rightColumnContent">
        <div class="column-content">
          <!-- 流式渲染 Markdown（仅当选中markmap类型智能体时显示） -->
          <div
            v-if="props.streamingMarkdown && props.streamingMarkdown.length > 0 && agentList[selectedAgentIndex]?.type === 'markmap'"
            class="agent-content streaming-content">
            <!-- <div class="streaming-label">思维导图实时生成中...</div> -->
            <MindMap :received-message="props.streamingMarkdown" :show-mind-map="true" :is-history-mode="false"
              ref="mindMapRef" />
          </div>

          <!-- 如果选中的是markmap类型智能体(思维导图),显示思维导图 -->
          <MindMap v-else-if="agentList[selectedAgentIndex]?.type === 'markmap'" :received-message="receivedMessage"
            :show-mind-map="true" :is-history-mode="isHistoryDataMode"
            @mindmap-loading-completed="onMindMapLoadingCompleted" ref="mindMapRef" />

          <!-- 如果选中的是gantt类型智能体(甘特图),显示甘特图 -->
          <GanttChart v-else-if="agentList[selectedAgentIndex]?.type === 'gantt'" :received-message="receivedMessage" :is-loading="props.isGanttLoading" />

          <!-- 否则显示选中节点的文本内容 -->
          <div v-else-if="currentAgentNodes.length > 0 && currentAgentNodes[selectedNodeIndex]" class="agent-content">
            <div v-html="renderContentWithLoading(currentAgentNodes[selectedNodeIndex].content)">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * MachineDetail 详情组件
 * 
 * 功能描述：
 * 1. 展示智能体执行的详细过程和结果
 * 2. 支持多种展示形式：节点列表、Markdown文本、思维导图(Markmap)
 * 3. 处理流式数据渲染和历史数据回放
 * 4. 自动根据数据状态切换选中的智能体和节点
 * 
 * 组件结构：
 * - 顶部：卡片基本信息栏 (Card Info)
 * - 左侧：智能体列表 (Agent List)
 * - 中间：节点列表 (Node List, 仅当智能体类型为node时显示)
 * - 右侧：详细内容展示区 (Content Area)
 */

import { ref, watch, computed, nextTick, onUnmounted } from 'vue'
import { marked } from 'marked'
import MindMap from '../MachineDetail/MindMap.vue'
import GanttChart from '../MachineDetail/GanttChart.vue'

// ==================== 组件接口 ====================

/** 组件 Props 定义 */
interface Props {
  /** 历史记录数据对象 */
  historyData: any
  /** 流式 Markdown 内容（用于思维导图实时渲染） */
  streamingMarkdown?: string
  /** 卡片基本信息（计划名称、时间等） */
  cardInfo?: any
  /** Gantt智能体加载状态（从父组件传入） */
  isGanttLoading?: boolean
}

const props = defineProps<Props>()

// 图片资源路径
const tipsIcon = new URL('../../assets/MachineDetail/icon-tips.png', import.meta.url).href
const textIcon = new URL('../../assets/MachineDetail/icon-text.png', import.meta.url).href
const shijianImage = new URL('../../assets/MachineDetail/node-timeline-active.png', import.meta.url).href
const shiImage = new URL('../../assets/MachineDetail/node-end-active.png', import.meta.url).href
const kongjianImage = new URL('../../assets/MachineDetail/node-timeline-inactive.png', import.meta.url).href
const kongImage = new URL('../../assets/MachineDetail/node-end-inactive.png', import.meta.url).href
const jiantouImage = new URL('../../assets/MachineDetail/icon-arrow-selected.png', import.meta.url).href
const selectJianImage = new URL('../../assets/MachineDetail/node-bg-selected.png', import.meta.url).href
const selectNoJianImage = new URL('../../assets/MachineDetail/node-bg-selected-end.png', import.meta.url).href
const checkImage = new URL('../../assets/MachineDetail/icon-check-small.png', import.meta.url).href
const notCheckImage = new URL('../../assets/MachineDetail/icon-uncheck-small.png', import.meta.url).href
const nullImage = new URL('../../assets/Common/state-empty.png', import.meta.url).href

// 响应式变量
const mindMapRef = ref<any>(null)
const rightColumnContent = ref<HTMLElement | null>(null)
const isTyping = ref<boolean>(false)
let typingTimer: any = null
let ganttSwitchTimer: any = null

const selectedAgentIndex = ref<number>(0)
const selectedNodeIndex = ref<number>(0)
const currentAgentType = ref<string>('')

// 思维导图是否已完成渲染
const isMindMapCompleted = ref<boolean>(false)

// 当前节点进度百分比
const currentNodeProgress = ref<number>(0)

// 渲染内容并注入加载指示器
const renderContentWithLoading = (content: string) => {
  let html = marked(content) as string
  
  // 判断是否需要显示加载指示器
  const shouldShowLoading = isTyping.value && 
    selectedAgentIndex.value === agentList.value.length - 1 && 
    selectedNodeIndex.value === currentAgentNodes.value.length - 1

  if (shouldShowLoading) {
    const loadingSpan = '<span class="loading-indicator"></span>'
    const lastCloseTagIndex = html.lastIndexOf('</')
    if (lastCloseTagIndex !== -1) {
      return html.slice(0, lastCloseTagIndex) + loadingSpan + html.slice(lastCloseTagIndex)
    }
    return html + loadingSpan
  }
  
  return html
}

// 计算属性: 实时从historyData 构建智能体列表
const agentList = computed(() => {
  if (!props.historyData || !props.historyData.screen2 || props.historyData.screen2.length === 0) {
    return []
  }

  const screen2Data = props.historyData.screen2
  let agentNamesIndex = -1
  let startIndex = 1

  for (let i = 0; i < screen2Data.length; i++) {
    if (Array.isArray(screen2Data[i])) {
      agentNamesIndex = i
      startIndex = i + 1
      break
    }
  }

  if (agentNamesIndex === -1) {
    return []
  }

  const allAgentNames = screen2Data[agentNamesIndex]
  const agents = allAgentNames.map((name: string) => ({
    name,
    type: '',
    nodes: [] as any[],
    hasData: false
  }))

  for (let i = startIndex; i < screen2Data.length; i++) {
    const item = screen2Data[i]
    const agentNames = Object.keys(item).filter(key => key !== 'layout')
    if (agentNames.length === 0) continue

    const agentName = agentNames[0]
    const agentType = item.layout
    const messages = item[agentName]
    const isStreaming = item._streaming || false // 获取流式标记

    const agent = agents.find((a: any) => a.name === agentName)
    if (!agent) continue

    agent.type = agentType
    agent.hasData = true
    agent.isStreaming = isStreaming // 传递流式状态

    if (agentType === 'node') {
      agent.nodes = messages.map((msg: any) => ({
        nodeId: msg.nodeName || '未知节点',
        content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
        completed: msg.hasOwnProperty('completed') ? msg.completed : true
      }))
    } else if (agentType === 'text' || agentType === 'summary') {
      agent.nodes = messages.map((msg: any) => ({
        nodeId: '内容',
        content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
        completed: msg.hasOwnProperty('completed') ? msg.completed : true
      }))
    } else if (agentType === 'markmap' || agentType === 'gantt') {
      agent.nodes = []
    }
  }

  return agents
})

// 计算属性: 当前选中智能体的节点列表
const currentAgentNodes = computed(() => {
  const agent = agentList.value[selectedAgentIndex.value]
  return agent ? agent.nodes : []
})

// 计算属性: 实时获取当前选中智能体的markmap内容
const receivedMessage = computed(() => {
  if (!props.historyData || !props.historyData.screen2) return ''

  const currentAgent = agentList.value[selectedAgentIndex.value]
  if (!currentAgent || (currentAgent.type !== 'markmap' && currentAgent.type !== 'gantt')) return ''

  const screen2Data = props.historyData.screen2

  for (let i = 1; i < screen2Data.length; i++) {
    const item = screen2Data[i]
    if (item.tag === 'isDone') break

    const agentNames = Object.keys(item).filter(key => key !== 'layout')
    if (agentNames.length === 0) continue

    const agentName = agentNames[0]
    if (agentName === currentAgent.name && (item.layout === 'markmap' || item.layout === 'gantt')) {
      const messages = item[agentName]
      
      if (item.layout === 'gantt') {
        if (messages && typeof messages === 'object' && !Array.isArray(messages)) {
          return messages
        }
      }
      
      const mindMapContent = messages[0]?.content
      if (mindMapContent) {
        return typeof mindMapContent === 'string' ? mindMapContent : JSON.stringify(mindMapContent)
      }
      break
    }
  }

  return ''
})

// 计算属性: 是否显示中间栏
const shouldShowMiddleColumn = computed(() => {
  const agent = agentList.value[selectedAgentIndex.value]
  return agent?.type === 'node'
})

// 计算属性: 判断是否为历史数据场景
const isHistoryDataMode = computed(() => {
  if (agentList.value.length === 0) return false
  return agentList.value.every((agent: any) => {
    if (!agent.hasData) return false
    if (agent.nodes.length === 0) {
      return isMindMapCompleted.value
    }
    return agent.nodes.every((node: any) => node.completed === true)
  })
})

// 计算属性: 已接收数据的智能体数量
const receivedAgentsCount = computed(() => {
  return agentList.value.filter((a: any) => a.hasData).length
})

// 监听已接收数据的智能体数量,实现自动切换
watch(receivedAgentsCount, (newCount, oldCount) => {
  // 当第一个智能体接收到数据时,自动选中
  if (oldCount === 0 && newCount > 0) {
    selectedAgentIndex.value = 0
    selectedNodeIndex.value = 0
    const firstAgent = agentList.value[0]
    currentAgentType.value = firstAgent?.type || ''
    console.log('MachineDetail自动选中第一个智能体:', firstAgent?.name, '类型:', firstAgent?.type)
  }

  // 当新智能体接收完成时,自动切换到该智能体
  if (newCount > oldCount && newCount > 1) {
    // 找到最新接收到数据的智能体
    const agents = agentList.value
    for (let i = 0; i < agents.length; i++) {
      if (agents[i].hasData && i > selectedAgentIndex.value) {
        
        // 特殊处理 Gantt 智能体
        if (agents[i].type === 'gantt') {
           // 如果还在流式传输中(占位状态)，只切换选中，不关闭遮罩
           if (agents[i].isStreaming) {
             console.log('[MachineDetail] 检测到Gantt智能体占位数据(流式中)，仅切换选中，不关闭遮罩')
             // 立即切换到Gantt智能体
             selectedAgentIndex.value = i
             selectedNodeIndex.value = 0
             currentAgentType.value = 'gantt'
             return
           }
           // 如果直接是非流式状态(完整数据)，由下方的 isStreaming watcher 处理，或者这里也可以切换
           // 但通常 SSE 场景下都是先占位后完整，所以主要逻辑在 isStreaming watcher
        }
        
        // 关键逻辑：如果前一个智能体是思维导图，且正在流式渲染，现在切换到下一个智能体，说明思维导图已完成
        const previousAgent = agents[selectedAgentIndex.value]
        if (previousAgent && previousAgent.type === 'markmap' && props.streamingMarkdown && props.streamingMarkdown.length > 0) {
          console.log('[MachineDetail] 检测到从思维导图切换到下一个智能体，标记思维导图为完成')
          isMindMapCompleted.value = true
        }

        selectedAgentIndex.value = i
        selectedNodeIndex.value = 0
        currentAgentType.value = agents[i].type || ''
        console.log('MachineDetail自动切换到新智能体:', agents[i].name, '类型:', agents[i].type)
        break
      }
    }
  }
})

// 监听agentList变化,检测历史数据场景
watch(agentList, (newAgentList, oldAgentList) => {
  console.log('[MachineDetail] agentList变化, 新长度:', newAgentList.length, '旧长度:', oldAgentList?.length || 0)

  if (newAgentList.length === 0) return

  // 历史数据场景的特征：
  // 1. 所有智能体都有数据（关键条件）
  // 2. 所有节点都已完成
  // 3. agentList从空数组一次性填充（区分于实时传输的逐个添加）
  const allAgentsHaveData = newAgentList.every((agent: any) => agent.hasData)

  console.log('[MachineDetail] 所有智能体都有数据:', allAgentsHaveData)

  if (!allAgentsHaveData) {
    // 实时传输场景：还有智能体没有数据，不触发历史数据逻辑
    return
  }

  // 关键判断：只有在agentList从无到有一次性填充时，才是历史数据场景
  // 实时传输场景下，agentList是逐个增加的
  const isOneTimeLoad = (!oldAgentList || oldAgentList.length === 0) && newAgentList.length > 1

  console.log('[MachineDetail] 是否一次性加载:', isOneTimeLoad, 'oldLength:', oldAgentList?.length, 'newLength:', newAgentList.length)

  if (!isOneTimeLoad) {
    // 不是一次性加载，是实时传输场景
    return
  }

  // 检查是否所有智能体的所有节点都已完成
  const allAgentsCompleted = newAgentList.every((agent: any) => {
    if (!agent.hasData) return false
    // markmap类型：历史数据场景下默认视为已完成
    if (agent.nodes.length === 0) {
      return true  // 历史数据场景下，思维导图默认完成
    }
    return agent.nodes.every((node: any) => node.completed === true)
  })

  console.log('[MachineDetail] 所有智能体都已完成:', allAgentsCompleted)

  // 如果是历史数据场景,自动选择最后一个智能体
  if (allAgentsCompleted && newAgentList.length > 0) {
    const lastAgentIndex = newAgentList.length - 1
    selectedAgentIndex.value = lastAgentIndex
    selectedNodeIndex.value = 0
    currentAgentType.value = newAgentList[lastAgentIndex].type || ''
    // 历史数据场景下，标记思维导图为已完成
    isMindMapCompleted.value = true
    console.log('历史数据场景: 自动选择最后一个智能体:', newAgentList[lastAgentIndex].name)
  }
}, { immediate: true })

// 计算属性: 当前智能体已完成的节点数量
const completedNodesCount = computed(() => {
  const currentAgent = agentList.value[selectedAgentIndex.value]
  if (!currentAgent || currentAgent.type !== 'node') {
    return 0
  }
  return currentAgent.nodes.filter((node: any) => node.completed).length
})

// 监听当前智能体的已完成节点数量,实现节点自动切换
watch(completedNodesCount, (newCount, oldCount) => {
  const currentAgent = agentList.value[selectedAgentIndex.value]

  // 只有type='node'的智能体才需要自动切换节点
  if (!currentAgent || currentAgent.type !== 'node') {
    return
  }

  // 当节点完成数量增加时,检查当前显示的节点是否完成
  if (newCount > oldCount && newCount > 0) {
    const currentNode = currentAgent.nodes[selectedNodeIndex.value]

    // 如果当前显示的节点已完成,且还有下一个节点,则切换到下一个节点
    if (currentNode && currentNode.completed && selectedNodeIndex.value < currentAgent.nodes.length - 1) {
      selectedNodeIndex.value += 1
      console.log('MachineDetail当前节点完成,切换到下一个节点:', currentAgent.nodes[selectedNodeIndex.value]?.nodeId)
    }
  }
})

// 监听流式Markdown的变化，检测流式渲染是否完成
watch(() => props.streamingMarkdown, (newVal, oldVal) => {
  // 当streamingMarkdown从有值变为空字符串时，说明流式渲染完成
  if (oldVal && oldVal.length > 0 && (!newVal || newVal.length === 0)) {
    console.log('[MachineDetail] 流式渲染完成，思维导图标记为完成')
    isMindMapCompleted.value = true
  }
  // 当streamingMarkdown从空变为有值时，说明开始新的流式渲染
  else if ((!oldVal || oldVal.length === 0) && newVal && newVal.length > 0) {
    console.log('[MachineDetail] 开始新的流式渲染，重置思维导图状态')
    isMindMapCompleted.value = false
  }
})

// 监听当前选中智能体的流式状态变化，用于处理Gantt遮罩关闭
watch(() => agentList.value[selectedAgentIndex.value]?.isStreaming, (newIsStreaming, oldIsStreaming) => {
  // 只有当从 true 变为 false (流式结束)，且当前是 Gantt 类型时触发
  if (oldIsStreaming === true && newIsStreaming === false) {
    const currentAgent = agentList.value[selectedAgentIndex.value]
    if (currentAgent && currentAgent.type === 'gantt') {
       console.log('[MachineDetail] Gantt 智能体流式传输结束(占位->完整)，关闭遮罩')
       
       // 1. 标记前一个思维导图为完成
       if (props.streamingMarkdown && props.streamingMarkdown.length > 0) {
         isMindMapCompleted.value = true
       }

       // 2. 发送关闭遮罩消息
       if (window.electronAPI?.sendDirectMessage) {
         window.electronAPI.sendDirectMessage('machine', {
           type: 'gantt_loading_complete',
           timestamp: new Date().toISOString()
         }).catch((error: Error) => {
           console.error('[MachineDetail] 发送gantt_loading_complete消息失败:', error)
         })
       }
       
       // 3. 启动延迟切换到下一个智能体的计时器
       if (ganttSwitchTimer) clearTimeout(ganttSwitchTimer)
       ganttSwitchTimer = setTimeout(() => {
          const nextIndex = agentList.value.findIndex((a: any, idx: number) => idx > selectedAgentIndex.value && a.hasData)
          if (nextIndex !== -1) {
              selectedAgentIndex.value = nextIndex
              selectedNodeIndex.value = 0
              currentAgentType.value = agentList.value[nextIndex].type || ''
              console.log('MachineDetail (Gantt展示后) 自动切换到下一个智能体:', agentList.value[nextIndex].name)
          }
       }, 2000) // 延迟2秒展示Gantt图表
    }
  }
})

// 选择智能体
const selectAgent = (index: number) => {
  if (index >= 0 && index < agentList.value.length) {
    const agent = agentList.value[index]

    // 只允许选择已接收数据的智能体
    if (!agent.hasData) {
      console.log('智能体尚未接收数据,无法选择:', agent.name)
      return
    }

    selectedAgentIndex.value = index
    selectedNodeIndex.value = 0 // 默认选中第一个节点
    currentAgentType.value = agent.type || ''

    console.log('MachineDetail选中智能体:', agent.name, '类型:', agent.type, '是否显示中栏:', shouldShowMiddleColumn.value)
  }
}

// 选择节点
const selectNode = (index: number) => {
  selectedNodeIndex.value = index
}

// 计算属性：获取每个智能体的背景图
const agentImages = computed(() => {
  // 强制读取isMindMapCompleted，确保Vue追踪这个依赖
  const mindMapCompleted = isMindMapCompleted.value

  return agentList.value.map((agent: any, agentIndex: number) => {
    const isLastAgent = agentIndex === agentList.value.length - 1
    const isSelected = agentIndex === selectedAgentIndex.value

    // 未接收数据的智能体显示空状态
    if (!agent || !agent.hasData) {
      return isLastAgent ? kongImage : kongjianImage
    }

    // 直接在这里判断完成状态
    let isCompleted = false

    if (agent.type === 'markmap') {
      // 思维导图智能体：使用mindMapCompleted状态
      // 检查是否所有其他智能体都已完成(历史数据场景)
      const allOtherAgentsCompleted = agentList.value.every((a: any, idx: number) => {
        if (idx === agentIndex) return true
        if (!a || !a.hasData || a.nodes.length === 0) return false
        return a.nodes.every((node: any) => node.completed)
      })

      const isHistoryMode = allOtherAgentsCompleted && agent.hasData && (!props.streamingMarkdown || props.streamingMarkdown.length === 0)
      isCompleted = isHistoryMode ? true : mindMapCompleted
    } else if (agent.type === 'gantt') {
      // 甘特图智能体：只要接收到数据就视为完成（目前没有流式加载状态）
      isCompleted = true
    } else {
      // 其他智能体：检查所有节点是否完成
      isCompleted = agent.nodes.length > 0 && agent.nodes.every((node: any) => node.completed)
    }

    // 返回对应的背景图
    if (isLastAgent) {
      // 最后一个节点：选中时显示 selectNoJianImage，否则根据完成状态显示
      if (isSelected && isCompleted) {
        return selectNoJianImage
      }
      return isCompleted ? shiImage : kongImage
    } else {
      // 非最后一个节点：选中时显示 selectJianImage，否则根据完成状态显示
      if (isSelected && isCompleted) {
        return selectJianImage
      }
      return isCompleted ? shijianImage : kongjianImage
    }
  })
})

// 思维导图加载完成事件处理
// 思维导图加载完成事件处理
const onMindMapLoadingCompleted = () => {
  // 只在历史数据模式下标记为完成（实时渲染模式由切换智能体逻辑处理）
  if (isHistoryDataMode.value) {
    isMindMapCompleted.value = true
  }
}

// 自动滚动到右侧栏底部的函数
const scrollToBottom = () => {
  nextTick(() => {
    if (rightColumnContent.value) {
      rightColumnContent.value.scrollTop = rightColumnContent.value.scrollHeight
    }
  })
}

// 监听当前选中节点的内容变化，自动滚动到底部并更新进度条
watch(
  () => currentAgentNodes.value[selectedNodeIndex.value]?.content,
  (newContent, oldContent) => {
    const currentAgent = agentList.value[selectedAgentIndex.value]
    const currentNode = currentAgentNodes.value[selectedNodeIndex.value]

    // 只有在非markmap类型时才处理
    if (currentAgent?.type !== 'markmap' && currentNode) {
      // 标记正在打字
      isTyping.value = true
      if (typingTimer) clearTimeout(typingTimer)
      typingTimer = setTimeout(() => {
        isTyping.value = false
      }, 1000)

      // 自动滚动到底部
      scrollToBottom()

      // 更新进度条
      if (!currentNode.completed && newContent) {
        const contentLength = newContent.length
        const oldLength = oldContent ? oldContent.length : 0

        // 如果内容在增长，说明正在打字
        if (contentLength > oldLength) {
          // 假设一个合理的最大长度来计算进度
          // 这里我们动态计算：如果内容还在增长，进度不超过95%，留5%给完成状态
          const estimatedMaxLength = contentLength * 1.1 // 预估还会增长10%
          const progress = Math.min((contentLength / estimatedMaxLength) * 100, 95)
          currentNodeProgress.value = progress
        }
      } else if (currentNode.completed) {
        // 节点完成时，进度到100%
        currentNodeProgress.value = 100
      }
    }
  },
  { flush: 'post' } // 确保在DOM更新后执行
)

// 监听节点完成状态，确保进度条达到100%
watch(
  () => currentAgentNodes.value[selectedNodeIndex.value]?.completed,
  (isCompleted) => {
    if (isCompleted) {
      currentNodeProgress.value = 100
    }
  }
)

// 监听选中的智能体或节点切换，重置进度并滚动到顶部
watch([selectedAgentIndex, selectedNodeIndex], () => {
  // 重置进度条
  currentNodeProgress.value = 0

  nextTick(() => {
    if (rightColumnContent.value) {
      rightColumnContent.value.scrollTop = 0
    }
  })
})

// 组件卸载
onUnmounted(() => {
  if (ganttSwitchTimer) clearTimeout(ganttSwitchTimer)
  if (typingTimer) clearTimeout(typingTimer)
})
</script>

<style scoped>

/* 加载指示器 - 旋转圆圈 */
:deep(.loading-indicator) {
  display: inline-block !important;
  width: 14px !important;
  height: 14px !important;
  margin-left: 5px !important;
  border: 2px solid #00FF9D !important;
  border-top-color: transparent !important;
  border-radius: 50% !important;
  animation: spin 1s linear infinite !important;
  vertical-align: middle !important;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Loading 遮罩层样式 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  gap: 20px;
  z-index: 1000;
}

/* Loading GIF 样式 */
.loading-gif {
  width: 80px;
  height: 80px;
  object-fit: contain;
}

.loading-text {
  font-family: 'Source Han Sans', sans-serif;
  font-size: 16px;
  font-weight: 400;
  color: #D4FFEF;
  opacity: 0.8;
  animation: pulse 1.5s ease-in-out infinite;
  height: auto !important;
  margin: 0;
}

@keyframes pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* 根包裹元素 */
.machine-detail-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
}

/* 卡片信息显示栏 */
.card-info-bar {
  position: fixed;
  top: 90px;
  left: 65px;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 30px;
  padding: 10px 20px;
  z-index: 10;
}

.info-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tips-icon {
  width: 16px;
  height: 16px;
  object-fit: contain;
}

.info-text {
  font-family: 'Source Han Sans', sans-serif;
  font-size: 16px;
  color: #D4FFEF;
  white-space: nowrap;
  font-weight: 500;
}

/* 综述结论长条 */
.summary-bar {
  background: rgba(0, 255, 192, 0.25);
  display: flex;
  align-items: center;
  padding: 9px 16px;
  gap: 6px;
  margin-top: 10px;
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.summary-icon {
  width: 20px;
  height: 20px;
  object-fit: contain;
}

.summary-text {
  font-family: 'Source Han Sans', sans-serif;
  font-size: 16px;
  font-weight: bold;
  line-height: normal;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
}

/* 三栏布局 */
.three-column-layout {
  display: flex;
  height: 91.7%;
  gap: 0;
  border: 1px solid rgba(255, 255, 255, 0.3);
}

/* 左侧栏 */
.left-column {
  width: 7.5%;
  border-right: 1px solid rgba(255, 255, 255, 0.3);
}

/* 左侧栏节点样式 */
.left-column .column-content {
  padding: 12px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.node-item {
  position: relative;
  width: 98px;
  height: 125px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  transition: opacity 0.3s ease;
}

.node-item:hover {
  opacity: 0.8;
}

/* 未接收数据的智能体样式 */
.node-item.no-data {
  opacity: 0.4;
  cursor: not-allowed;
}

.node-item.no-data:hover {
  opacity: 0.4;
}

.node-bg {
  width: 98px;
  height: 131px;
  object-fit: cover;
  display: block;
}

.node-text {
  position: absolute;
  top: 37%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: Source Han Sans;
  font-size: 12px;
  font-weight: bold;
  line-height: 1.2;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
  pointer-events: none;
  text-align: center;
  width: 90%;
  word-break: break-all;
}

.node-arrow {
  position: absolute;
  right: -10px;
  top: 37%;
  transform: translateY(-50%);
  width: 10px;
  height: 14px;
  object-fit: contain;
  z-index: 10;
}

/* 中间栏 */
.middle-column {
  width: 10.7%;
  border-right: 1px solid rgba(255, 255, 255, 0.3);
  overflow-y: auto;
}

/* 中间栏内容样式 */
.middle-column .column-content {
  padding: 0;
}

.middle-title {
  width: 100%;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Source Han Sans', sans-serif;
  font-size: 14px;
  font-weight: bold;
  line-height: normal;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
  border-bottom: 1px solid rgba(255, 255, 255, 0.3);
}

.middle-item {
  width: 100%;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 15px;
  box-sizing: border-box;
  border-bottom: 1px solid rgba(255, 255, 255, 0.3);
  position: relative;
  overflow: hidden;
  cursor: pointer;
  transition: background 0.3s ease;
}

.middle-item:hover {
  background: rgba(255, 255, 255, 0.05);
}

.middle-item.selected {
  background: rgba(255, 255, 255, 0.1);
}

.middle-item-text {
  font-family: 'Source Han Sans', sans-serif;
  font-size: 14px;
  font-weight: normal;
  line-height: normal;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
  position: relative;
  z-index: 2;
}

.middle-item-icon {
  width: 14px;
  height: 14px;
  object-fit: contain;
  flex-shrink: 0;
  position: relative;
  z-index: 2;
}

/* 节点进度条样式 */
.node-progress-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  height: 100%;
  /* 高度占满 */
  width: 0%;
  /* 初始宽度为0，由JS动态控制 */
  background: linear-gradient(to right, transparent 0%, #00ebb1 100%);
  /* 水平渐变 */
  z-index: 1;
  opacity: 1;
  transition: width 0.3s ease-out, opacity 0.3s ease-out;
  /* 平滑过渡 */
}

/* 进度条淡出动画（当节点完成时） */
@keyframes fadeOut {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

.node-progress-bar.fade-out {
  animation: fadeOut 0.3s ease-out forwards;
  /* 淡出动画 */
}

/* 右侧栏 */
.right-column {
  width: 100%;
  height: 770px;
  overflow-y: auto;
}

/* 右侧栏全宽（思维导图智能体时） */
.right-column.full-width {
  width: 92.5%;
}

/* 右侧栏文字样式 */
.right-column .column-content {
  position: relative;
  padding: 20px;
  box-sizing: border-box;
  font-family: 'Source Han Sans', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 26px;
  letter-spacing: 0em;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
  /* overflow-y: auto; */
  height: 100%;
}

/* 右侧栏内容滚动条样式 */
.right-column .column-content::-webkit-scrollbar {
  width: 6px;
}

.right-column .column-content::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
}

.right-column .column-content::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
}

.right-column .column-content::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.5);
}

.right-column .column-content p {
  font-family: 'Source Han Sans', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 26px;
  letter-spacing: 0em;
  font-feature-settings: "kern" on;
  color: #D4FFEF;
  margin: 10px 0;
}

/* 智能体内容样式 */
.agent-content {
  margin-bottom: 20px;
  height: 100%;
}

.agent-content p {
  margin: 10px 0;
}

/* 思维导图加载提示样式 */
.loading-mindmap-tip {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #D4FFEF;
  font-family: 'Source Han Sans', sans-serif;
  font-size: 16px;
  opacity: 0.8;
  gap: 20px;
}

.loading-mindmap-tip .processing-gif {
  width: 80px;
  height: 80px;
  object-fit: contain;
}

.loading-mindmap-tip p {
  animation: pulse 1.5s ease-in-out infinite;
  height: auto !important;
  margin: 0;
}

/* 滚动条样式 */
.left-column::-webkit-scrollbar,
.middle-column::-webkit-scrollbar,
.right-column::-webkit-scrollbar {
  width: 6px;
}

.left-column::-webkit-scrollbar-track,
.middle-column::-webkit-scrollbar-track,
.right-column::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
}

.left-column::-webkit-scrollbar-thumb,
.middle-column::-webkit-scrollbar-thumb,
.right-column::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
}

.left-column::-webkit-scrollbar-thumb:hover,
.middle-column::-webkit-scrollbar-thumb:hover,
.right-column::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.5);
}

/* 动画 */
@keyframes pulse {

  0%,
  100% {
    opacity: 0.8;
  }

  50% {
    opacity: 1;
  }
}

/* 流式渲染样式 */
.streaming-content {
  animation: fadeIn 0.3s ease-in;
}

.streaming-label {
  color: #4CAF50;
  font-size: 14px;
  margin-bottom: 10px;
  padding: 5px 10px;
  background: rgba(76, 175, 80, 0.1);
  border-left: 3px solid #4CAF50;
  animation: pulse 1.5s infinite;
}

.streaming-chunk {
  margin-bottom: 15px;
  padding: 10px;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 4px;
  animation: slideInRight 0.3s ease-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes slideInRight {
  from {
    transform: translateX(20px);
    opacity: 0;
  }

  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* 空数据状态 */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 91.7%;
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.empty-icon img {
  width: 192px;
  height: 154px;
  object-fit: contain;
}
</style>
